<template>
  <div>
    <el-dialog v-if="enable" :visible.sync="enable">
      <div slot="title">
        <span style="padding-right:10px;">用户权限 : {{user.User}}</span>
        <el-button size="mini" @click="actionPrivilegeEditOpen">添加权限</el-button>
      </div>

      <el-card class="box-card mb-1" v-for="(item, index) in privileges" :key="index">
        <div class="mb-1">
          <el-button size="mini" class="float-right"
            @click="actionRevokePrivilege(index)"
          >取消授权</el-button>
          {{item.name}}
        </div>
        {{item.privileges}}
      </el-card>
    </el-dialog>

    <el-dialog v-if="privilegeEditEnable" :visible.sync="privilegeEditEnable" :title="`权限编辑 用户：${user.User}`">
      <el-form ref="form" :model="privilegeEditModel" label-width="80px">
        <el-form-item label="对象">
          <el-radio-group v-model="privilegeEditModel.targetType" @change="actionHandlePrivilegeEditTargetTypeChange">
            <el-radio label="global">全局</el-radio>
            <el-radio label="specified">指定目标</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="数据库" v-if="'specified' == privilegeEditModel.targetType">
          <el-select v-model="privilegeEditModel.database" placeholder="请选择数据库" 
            @change="actionHandlePrivilegeEditDatabaseChange"
            class="w-100"
          >
            <el-option label="所有" value="*"></el-option>
            <el-option v-for="item in privilegeEditDatabases" :key="item" :label="item" :value="item"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="数据表" v-if="'specified' == privilegeEditModel.targetType">
          <el-select v-model="privilegeEditModel.table" placeholder="请选择数据表" class="w-100">
            <el-option label="所有" value="*"></el-option>
            <el-option v-for="item in privilegeEditTables" :key="item" :label="item" :value="item"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="权限">
          <div>
            <el-button size="mini" @click="actionPrivilegeEditPrivilegeSelectAll">全选</el-button>
            <el-button size="mini" @click="actionPrivilegeEditPrivilegeSelectNone">取消选择</el-button>
          </div>
          <el-checkbox-group v-model="privilegeEditModel.privileges" style="max-height:200px;overflow: auto;">
            <el-checkbox v-for="item in privilegeList" 
              :key="item.name" 
              :label="item.name" 
              :name="item.name"
              style="width:40%"
            ></el-checkbox>
          </el-checkbox-group>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="privilegeEditEnable = false">取 消</el-button>
        <el-button type="primary" @click="actionPrivilegeEditUpdate">更 新</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
export default {
    name : 'DialogMysqlUserPrivilegeEdit',
    data() {
        return {
            enable : false,
            connection : null,
            user : null,
            privileges : [],

            privilegeEditEnable : false,
            privilegeEditDatabases : null,
            privilegeEditTables : [],
            privilegeEditModel : {
                targetType : 'global',
                privileges : [],
            },
        };
    },
    computed : {
        // 权限列表
        privilegeList() {
            let list = [
                {name:"ALTER",specified:true},
                {name:"ALTER ROUTINE",specified:false},
                {name:"CREATE",specified:true},
                {name:"CREATE ROLE",specified:false},
                {name:"CREATE ROUTINE",specified:false},
                {name:"CREATE TABLESPACE",specified:false},
                {name:"CREATE TEMPORARY TABLES",specified:false},
                {name:"CREATE USER",specified:false},
                {name:"CREATE VIEW",specified:true},
                {name:"DELETE",specified:true},
                {name:"DROP",specified:true},
                {name:"DROP ROLE",specified:false},
                {name:"EVENT",specified:false},
                {name:"EXECUTE",specified:false},
                {name:"FILE",specified:false},
                {name:"GRANT OPTION",specified:true},
                {name:"INDEX",specified:true},
                {name:"INSERT",specified:true},
                {name:"LOCK TABLES",specified:false},
                {name:"PROCESS",specified:false},
                {name:"REFERENCES",specified:true},
                {name:"RELOAD",specified:false},
                {name:"REPLICATION CLIENT",specified:false},
                {name:"REPLICATION SLAVE",specified:false},
                {name:"SELECT",specified:true},
                {name:"SHOW DATABASES",specified:false},
                {name:"SHOW VIEW",specified:true},
                {name:"SHUTDOWN",specified:false},
                {name:"SUPER",specified:false},
                {name:"TRIGGER",specified:true},
                {name:"UPDATE",specified:true},
                {name:"USAGE",specified:true},
            ];

            let display = [];
            for ( let i=0; i<list.length; i++ ) {
                if ( 'specified' == this.privilegeEditModel.targetType && true == list[i].specified) {
                    display.push(list[i]);
                }
                if ( 'global' == this.privilegeEditModel.targetType ) {
                    display.push(list[i]);
                }
            }
            return display;
        },
    },
    methods : {
        // 打开弹框
        async open( connection, user ) {
            this.connection = connection;
            this.user = user;
            await this.refreshDefinedPrivileges();
            this.enable = true;
        },

        // 刷新权限列表
        async refreshDefinedPrivileges() {
            this.privileges = [];
            
            let definations = await this.connection.execute(`SHOW GRANTS FOR ${this.user.User}@'${this.user.Host}'`);
            if ( 0 == definations.length ) {
                return;
            }

            let key = Object.keys(definations[0])[0];
            for ( let i=0; i<definations.length; i++ ) {
                let def = definations[i][key];
                let regex = /GRANT (?<privileges>.*?) ON (?<dbname>.*?)\.(?<tablename>.*?) TO (?<username>.*?)@(?<hostname>.*?)(?<grant> WITH GRANT OPTION)*$/;
                let defMatch = def.match(regex);
                if ( 0 == defMatch.length ) {
                    this.$message.error(`无法解析权限定义: ${def}`);
                    return;
                }

                let privilege = defMatch.groups;
                if ( 'USAGE' == privilege.privileges ) {
                    continue;
                }
                
                privilege.database = privilege.dbname;
                if ( '*' != privilege.dbname ) {
                    privilege.dbname = privilege.dbname.substr(1,privilege.dbname.length-2);
                }
                privilege.table = privilege.tablename;
                if ( '*' != privilege.tablename ) {
                    privilege.tablename = privilege.tablename.substr(1,privilege.tablename.length-2);
                }

                privilege.name = null;
                if ( '*' == privilege.dbname && '*' == privilege.tablename ) {
                    privilege.name = '全局';
                } else {
                    let dbname = ('*' == privilege.dbname) ? '所有数据库' : privilege.dbname;
                    let tablename = ('*' == privilege.tablename ) ? '所有表' : privilege.tablename;
                    privilege.name = `${dbname} : ${tablename}`;
                }
                if ( '`' == privilege.username[0] ) {
                    privilege.username = privilege.username.substr(1,privilege.username.length-2);
                }
                if ( '`' == privilege.hostname[0] ) {
                    privilege.hostname = privilege.hostname.substr(1,privilege.hostname.length-2);
                }
                this.privileges.push(privilege);
            }
        },

        // 打开编辑框
        actionPrivilegeEditOpen () {
            this.privilegeEditEnable = true;
            this.privilegeEditModel.privileges = [];
        },

        // 权限编辑目标类型变更
        async actionHandlePrivilegeEditTargetTypeChange() {
            if ( 'specified' == this.privilegeEditModel.targetType && null == this.privilegeEditDatabases) {
                this.privilegeEditDatabases = [];
                let dbnames = await this.connection.execute('show databases');
                for ( let i=0; i<dbnames.length; i++ ) {
                    this.privilegeEditDatabases.push(dbnames[i]['Database']);
                }
            }
            this.privilegeEditModel.privileges = [];
        },

        // 数据库编辑
        async actionHandlePrivilegeEditDatabaseChange() {
            this.privilegeEditTables = [];
            
            let name = this.privilegeEditModel.database;
            if ( '*' == name ) {
                this.privilegeEditModel.tables = ['*'];
            }
            let queryTable = `SELECT TABLE_NAME from information_schema.\`TABLES\` WHERE TABLE_SCHEMA='${name}'`;
            let tablelist = await this.connection.execute(queryTable);
            for ( let i=0; i<tablelist.length; i++ ) {
                this.privilegeEditTables.push(tablelist[i]['TABLE_NAME']);
            }
        },

        // 全选所有权限
        actionPrivilegeEditPrivilegeSelectAll() {
            this.privilegeEditModel.privileges = [];
            for ( let i=0; i<this.privilegeList.length; i++ ) {
                this.privilegeEditModel.privileges.push(this.privilegeList[i].name);
            }
            this.$forceUpdate();
        },

        // 取消权限选择
        actionPrivilegeEditPrivilegeSelectNone() {
            this.privilegeEditModel.privileges = [];
            this.$forceUpdate();
        },

        // 创建权限
        async actionPrivilegeEditUpdate() {
            if ( 0 == this.privilegeEditModel.privileges.length ) {
                this.$message.error('请指定授权权限');
                return;
            }

            let privileges = this.privilegeEditModel.privileges.join(',');
            let target = null;
            if ( 'global' == this.privilegeEditModel.targetType ) {
                target = '*.*';
            } else {
                let dbname = ('*' == this.privilegeEditModel.database) ? '*' : `\`${this.privilegeEditModel.database}\``;
                let tbname = ('*' == this.privilegeEditModel.table) ? '*' : `\`${this.privilegeEditModel.table}\``;
                target = `${dbname}.${tbname}`;
            }
            let sql = `GRANT ${privileges} ON ${target} TO \`${this.user.User}\`@\`${this.user.Host}\``;
            console.log(sql);
            try {
                await this.connection.execute(sql);
            } catch ( e ) {
                this.$message.error(e.message);
                return;
            }

            await this.connection.execute('FLUSH PRIVILEGES');

            this.privilegeEditEnable = false;
            await this.refreshDefinedPrivileges();
        },

        // 删除授权
        async actionRevokePrivilege(index) {
            try {
                await this.$confirm('此操作将取消该授权, 是否继续?', '提示', {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                });
            } catch {
                return;
            }

            let privilege = this.privileges[index];
            let dbname = privilege.database;
            let tablename = privilege.table;
            let sql = `REVOKE ${privilege.privileges} ON ${dbname}.${tablename} FROM '${privilege.username}'@'${privilege.hostname}'`;
            console.log(sql);
            try {
                await this.connection.execute(sql);
            } catch ( e ) {
                this.$message.error(e.message);
                return;
            }
            
            await this.connection.execute('FLUSH PRIVILEGES');
            await this.refreshDefinedPrivileges();
        },
    },
}
</script>